package com.symaster.common.connect.v2;

import com.alibaba.fastjson.JSONObject;
import com.symaster.common.connect.listener.MasterListener;
import com.symaster.common.connect.local.ConnectObj;
import com.symaster.common.connect.tcp.TcpElementR;
import com.symaster.common.connect.tcp.TcpElementW;
import com.symaster.common.connect.util.ClientCommon;
import com.symaster.common.util.IOUtil;

import java.io.Closeable;
import java.io.IOException;
import java.util.*;

/**
 * @author yinmiao
 * @version 2022-05-03 11:28
 */
public class Master extends MasterListener implements Closeable, MasterEnum {

    private final int port;
    private RegistrationCenter registrationCenter;
    private List<ConnectObj> connectObjList;
    private Map<String, ConnectObj> connectObjMap;

    public Master(int port) {
        this.port = port;
        startRegistrationCenter();
    }

    public List<ConnectObj> getAllConnect() {
        return connectObjList;
    }

    public void sendToAllConnect(String message) {
        if (connectObjList == null) {
            return;
        }
        for (ConnectObj connectObj : connectObjList) {
            try {
                ClientCommon._send(connectObj, message);
            } catch (IOException ignored) {
            }
        }
    }

    public void sendByUuid(String uuid, String message) {
        if (this.connectObjMap == null) {
            throw new IllegalArgumentException("不存在此连接");
        }
        ConnectObj connectObj = connectObjMap.get(uuid);
        if (connectObj == null) {
            throw new IllegalArgumentException("不存在此连接");
        }
        try {
            ClientCommon._send(connectObj, message);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public String sendAndWaitByUuid(String uuid, String message) {
        if (this.connectObjMap == null) {
            throw new IllegalArgumentException("不存在此连接");
        }
        ConnectObj connectObj = connectObjMap.get(uuid);
        if (connectObj == null) {
            throw new IllegalArgumentException("不存在此连接");
        }
        try {
            return ClientCommon._sendAndWait(connectObj, message);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void createConnectObj(RegistrationCenter.ConnectionRequestEntity e) {
        ConnectObj connectObj = new ConnectObj();
        connectObj.setIp(e.getIp());
        connectObj.setPort(e.getPort());

        try {
            connectObj.setTcpElementW(new TcpElementW(e.getIp(), e.getPort()));

            int randomPort = IOUtil.randomPort();
            TcpElementR tcpElementR = new TcpElementR(randomPort);
            tcpElementR.setConnectSuccessListener(() -> myConnectSuccessListener(connectObj));
            tcpElementR.setConnectClosedListener(() -> myConnectClosedListener(connectObj));
            tcpElementR.setMessageHandler(message -> {
                JSONObject jsonObject = JSONObject.parseObject(message);
                if (HANDLER_MESSAGE.equals(jsonObject.getString(EXECUTE))) {
                    return messageHandler(connectObj, jsonObject.getString(MESSAGE));
                }
                return null;
            });
            connectObj.setTcpElementR(tcpElementR);

            JSONObject jsonObject = new JSONObject();
            jsonObject.put(EXECUTE, CONNECT_ME);
            jsonObject.put(PORT, randomPort);
            connectObj.getTcpElementW().send(jsonObject.toJSONString());

        } catch (Exception ex) {
            IOUtil.close(connectObj);
        }
    }

    private void startRegistrationCenter() {
        registrationCenter = new RegistrationCenter(port);
        registrationCenter.setConnectionRequestListener(this::createConnectObj);
        registrationCenter.start();
    }

    private void myConnectSuccessListener(ConnectObj connectObj) {
        if (connectObjList == null) {
            connectObjList = new ArrayList<>();
            connectObjMap = new HashMap<>();
        }
        connectObjList.add(connectObj);
        connectObjMap.put(connectObj.getUuid(), connectObj);
        connectSuccessListener(connectObj);
    }

    private void myConnectClosedListener(ConnectObj connectObj) {
        if (connectObjList != null) {
            connectObjList.remove(connectObj);
        }
        if (connectObjMap != null) {
            IOUtil.close(connectObjMap.remove(connectObj.getUuid()));
        }
        connectClosedListener(connectObj, 0, null);
    }

    @Override
    public void close() throws IOException {
        IOUtil.close(registrationCenter);
        if (connectObjList != null && connectObjList.size() > 0)
            IOUtil.close(connectObjList.toArray(new ConnectObj[0]));
    }
}

